import numpy as np
import os
class go_board():
    board=np.zeros((3,3),dtype=np.int8)
    win_tab=np.zeros((8,3,3),dtype=np.int8)
    player_list=[1,2]

    def flash_board(self,player=None,x=None,y=None):
        os.system('cls')
        illegal = False
        if player!=None and x!=None and y!=None:
            try:
                x,y=int(x),int(y)
                if self.board[x,y]!=0: illegal = True
                else: 
                    self.board[x,y]=player
            except: illegal = True
        print(self.board)
        return illegal

    def init_win_tab(self):
        self.win_tab[0,:,0] = [1,1,1]
        self.win_tab[1,:,1] = [1,1,1]
        self.win_tab[2,:,2] = [1,1,1]
        self.win_tab[3,0,:] = [1,1,1]
        self.win_tab[4,1,:] = [1,1,1]
        self.win_tab[5,2,:] = [1,1,1]
        self.win_tab[6,0,0] = 1
        self.win_tab[6,1,1] = 1
        self.win_tab[6,2,2] = 1
        self.win_tab[7,0,2] = 1
        self.win_tab[7,1,1] = 1
        self.win_tab[7,2,0] = 1
        pass
    
    def win_check(self,board=None):
        if type(board) is not np.ndarray: board=self.board
        for player in self.player_list:
            player_filted = board==player
            for win_case in self.win_tab:
                win = np.sum(np.multiply(player_filted,win_case))>=3
                if win: return player
        return False

    def profit(self,player,board):
        win=self.win_check(board)
        if win:
            if win==player: return 999
            else: return -999
        player_filted = np.add(board==player,board==0)
        f = 0 #num of player's access of winning
        for win_case in self.win_tab:
            win = np.sum(np.multiply(player_filted,win_case))>=3
            if win: f+=1
        player_filted = np.add(board==3-player,board==0)
        g = 0 #num of opponent's access of winning
        for win_case in self.win_tab:
            win = np.sum(np.multiply(player_filted,win_case))>=3
            if win: g+=1
        return f-g

    def max_min_search(self,board,player,depth):
        result_list=[]
        for x in range(3):
            for y in range(3):
                if board[x,y]==0:
                    temp_board = np.copy(board)
                    temp_board[x,y]=player
                    if depth>1:
                        result = self.max_min_search(
                            temp_board,3-player,depth-1
                        )
                        result_list.append(((x,y),result[1]))
                    else:
                        profit = self.profit(3-player,temp_board)
                        result_list.append(((x,y),profit))
        if len(result_list)==0: result_list.append(((-1,-1),0))
        result_list.sort(
            key=lambda x:x[1], 
            reverse=False if player==self.human else True
        )
        return result_list[0]

    def AI_logic(self,depth=2):
        pos,profit = self.max_min_search(
            np.copy(self.board),self.AI,depth
        )
        return pos

    def game_loop(self):
        win = False
        player = 1
        steps = 0
        while not win:
            illegal = True
            while illegal:
                x,y=(-999,-999)
                try:
                    if player==self.human:
                        x,y = input(f'{player} goes at:')
                        pass # get human go
                    else:
                        x,y = self.AI_logic()
                        #print(f'AI goes at:{x}{y}')
                        pass # AI search
                except:
                    pass
                illegal = self.flash_board(player,x,y)
                win = self.win_check()
            player = 3-player
            steps+=1
            if steps==9: break
        if win:
            print(f'Player {win} Win!')
        else:
            print("Draw!")

    def __init__(self):
        self.init_win_tab()

        #self.board[1,1]=1
        try:
            human = int(input('Choose player 1 or 2:'))
            self.human = 1 if human not in self.player_list else human
        except:
            self.human = 1
        self.AI = 3-self.human
        #self.max_min_search()
        self.flash_board()
        self.game_loop()
        pass

go=go_board()